Skip to content

原文:异步与设计模式(12题)

[toc]

1. Promise 完整实现

推导链

Q1: Promise 是什么? → 状态机:pending → fulfilled/rejected,不可逆 → 需要:state、value、callbacks[]

Q2: resolve/reject 干嘛? → 改状态 + 存值 + 执行所有等待的回调 → 为什么要 callbacks?因为 then 可能在 pending 时调用

Q3: then 为什么能链式调用? → 返回新 Promise → 新 Promise 的 resolve/reject 由上一个 then 的返回值决定

Q4: then 的返回值怎么处理? → 普通值:直接 resolve(result) → Promise:result.then(resolve, reject) 等它完成

Q5: 为什么要 setTimeout? → 规范要求 then 回调异步执行

Q6: 透传是什么? → .then().then(v => ...) 值要能传下去 → 默认 v => v 和 e =>

代码

javascript
class MyPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.callbacks = [];

        const resolve = (val) => {
            if(this.state !== 'pending') return;
            this.state = 'fulfilled';
            this.value = val;
            this.callbacks.forEach(cb => cb.onFulfilled());
        }

        const reject = (val) => {
            if(this.state !== 'pending') return;
            this.state = 'rejected';
            this.value = val;
            this.callbacks.forEach(cb => cb.onRejected());
        }

        try {
            executor(resolve,reject);
        } catch (e) {
            reject(e);
        }
    }

    then(onFulfilled,onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e }

        return new MyPromise((resolve, reject) => {
            const handle = (callback) => {
                try {
                    const result = callback(this.value);
                    result instanceof MyPromise ? result.then(resolve,reject) : resolve(result);
                } catch (e) {
                    reject(e)
                }
            }

            if(this.state === 'fulfilled') return setTimeout(() => handle(onFulfilled));
            if(this.state === 'rejected') return setTimeout(() => handle(onRejected));

            this.callbacks.push({
                onFulfilled: () => setTimeout(() => handle(onFulfilled)),
                onRejected: () => setTimeout(() => handle(onRejected))
            })
        })
    }

    catch(onRejected) {
        return this.then(null,onRejected);
    }

    static resolve(v) {
        return v instanceof MyPromise ? v : new MyPromise(r => r(v));
    }
    static reject(e) {
        return new MyPromise((_,r) => r(e))
    }
}

//测试
const p1 = new MyPromise((resolve,reject) => {
    setTimeout(() => {
        resolve('成功')
    },1000)
})

p1.then(res => {
    console.log('p1: ', res);
})

2. Promise.all

推导链

Q1: all 干嘛?→ 全部成功才成功,一个失败就失败 Q2: 怎么知道全部完成?→ 计数器 finished === total Q3: 结果顺序?→ results[index] 按索引存

代码

javascript
Promise.myAll = function(promises) {
    return new Promise((resolve,reject) => {
        const results = [];
        let count = 0;
        const arr = Array.from(promises);
        
        if(arr.length === 0) return resolve([]);
        
        arr.forEach((p,i) => {
            Promise.resolve(p).then(value => {
                results[i] = value;
          		count++;
          		if (count === promises.length) resolve(results);
            }, reject);
        });
    });
}

// 测试
Promise.myAll([Promise.resolve(1), Promise.resolve(2), 3]).then(console.log) // [1,2,3]
Promise.myAll([Promise.resolve(1), Promise.reject('err')]).catch(console.log) // 'err'

3. Promise.race

推导链

Q1: race 干嘛?→ 谁先完成用谁(无论成功失败) Q2: 怎么实现?→ 每个都 .then(resolve, reject),第一个触发后状态锁定

代码

javascript
Promise.myRace = function(promises) {
    return new Promise((resolve,reject) => {
      promises.forEach(p => {
        Promise.resolve(p).then(resolve, reject);
      });
    })
}

// 测试
Promise.myRace([
  new Promise(r => setTimeout(() => r('slow'), 200)),
  new Promise(r => setTimeout(() => r('fast'), 100))
]).then(console.log) // 'fast'

4. Promise.any

推导链

Q1: 和 race 区别?→ 第一个成功的,全失败才失败 Q2: 全失败返回什么?→ AggregateError

代码

javascript
Promise.myAny = function(promises) {
    return new Promise((resolve,reject) => {
        const errors = [];
        let rejected = 0;
        const arr = Array.from(promises);
        
        if(arr.length === 0) return reject(new AggregateError([], 'All promises were rejected'))
        
        arr.forEach((p,i) => {
            Promise.resolve(p).then(resolve, reason => {
                errors[i] = reason;
                rejected++;
                if(rejected === arr.length) {
                    reject(new AggregateError([], 'All promises were rejected'))
                }
            });
        });
    });
}

// 测试
Promise.myAny([Promise.reject(1), Promise.resolve(2)]).then(console.log) // 2
Promise.myAny([Promise.reject(1), Promise.reject(2)]).catch(e => console.log(e.errors)) // [1,2]